{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Time Domain   and Gating"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Intro"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This notebooks demonstrates how to use [scikit-rf](http://scikit-rf.org) for time-domain analysis and gating. A quick example is given first, followed by a more detailed explanation.\n",
    "\n",
    "\n",
    "S-parameters are measured in the frequency domain, but can be analyzed in  time domain if you like. In many cases, measurements are not made down to DC. This implies that the  time-domain transform is not complete, but it can be very useful nonetheless. A major application of time-domain analysis is to use *gating* to isolate a single response in space. More information about the details of time domain analysis see [1]. \n",
    "\n",
    "\n",
    "References\n",
    "\n",
    "* [1] Keysight - Time Domain Analysis Using a Network Analyzer - Application Note [pdf](https://www.keysight.com/us/en/assets/7018-01451/application-notes/5989-5723.pdf)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Quick Example"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "\n",
    "import skrf as rf\n",
    "\n",
    "%matplotlib inline\n",
    "rf.stylely()\n",
    "\n",
    "# load data for the waveguide to CPW probe\n",
    "probe = rf.Network('../metrology/oneport_tiered_calibration/probe.s2p')\n",
    "\n",
    "# we will focus on s11\n",
    "s11 = probe.s11\n",
    "\n",
    "#  time-gate the first largest reflection\n",
    "s11_gated = s11.time_gate(center=0, span=.2, t_unit='ns')\n",
    "s11_gated.name='gated probe'\n",
    "\n",
    "# plot frequency and time-domain s-parameters\n",
    "plt.figure(figsize=(8,4))\n",
    "plt.subplot(121)\n",
    "s11.plot_s_db()\n",
    "s11_gated.plot_s_db()\n",
    "plt.title('Frequency Domain')\n",
    "\n",
    "plt.subplot(122)\n",
    "s11.plot_s_db_time()\n",
    "s11_gated.plot_s_db_time()\n",
    "plt.title('Time Domain')\n",
    "plt.tight_layout()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Interpreting Time Domain"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Out DUT in this example is a waveguide-to-CPW probe, that was measured in [this other example](../metrology/One Port Tiered Calibration.ipynb). "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# load data for the waveguide to CPW probe\n",
    "probe = rf.Network('../metrology/oneport_tiered_calibration/probe.s2p')\n",
    "probe"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note there are two  time-domain plotting functions in scikit-rf: \n",
    "\n",
    "* `Network.plot_s_db_time()`  \n",
    "* `Network.plot_s_time_db()`\n",
    "\n",
    "The difference is that the former, `plot_s_db_time()`, employs windowing before plotting to enhance impulse resolution. Windowing will be discussed in a bit, but for now we just use `plot_s_db_time()`.\n",
    "\n",
    "Plotting all four s-parameters of the probe in both frequency and time-domain."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# plot frequency and time-domain s-parameters\n",
    "plt.figure(figsize=(8,4))\n",
    "plt.subplot(121)\n",
    "probe.plot_s_db()\n",
    "plt.title('Frequency Domain')\n",
    "plt.subplot(122)\n",
    "probe.plot_s_db_time()\n",
    "plt.title('Time Domain')\n",
    "plt.tight_layout()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Focusing on  the reflection coefficient from the waveguide port (s11), you can see there is an interference pattern present."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "probe.plot_s_db(0,0)\n",
    "plt.title('Reflection Coefficient From \\nWaveguide Port')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This ripple is evidence of several discrete reflections. Plotting s11 in the time-domain allows us to see where, or *when*, these reflections occur."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "probe_s11 = probe.s11\n",
    "probe_s11.plot_s_db_time(0,0)\n",
    "plt.title('Reflection Coefficient From \\nWaveguide Port, Time Domain')\n",
    "plt.ylim(-100,0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "From this plot we can see two dominant reflections; \n",
    "\n",
    "* one at $t=0$ns (the test-port) \n",
    "* and another  at $t=.2$ ns (who knows?).\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Gating The Reflection of Interest"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To isolate the reflection from the waveguide port, we can use time-gating. This can be done by using the method `Network.time_gate()`, and provide it an appropriate center and span (in ns).  To see the effects of the gate, both the original and gated response are compared."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "probe_s11_gated = probe_s11.time_gate(center=0, span=.2, t_unit='ns')\n",
    "probe_s11_gated.name='gated probe'\n",
    "\n",
    "s11.plot_s_db_time()\n",
    "s11_gated.plot_s_db_time()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, compare both responses in frequency domain to see the effect of the gate. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "s11.plot_s_db()\n",
    "s11_gated.plot_s_db()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "###  Auto-gate \n",
    "\n",
    "The time-gating method in `skrf` has an auto-gating feature which can also be used to gate the largest reflection. When no gate parameters are provided, `time_gate()` does the following: \n",
    "\n",
    "1. find the two largest peaks\n",
    "* center the gate on the tallest peak\n",
    "* set span to distance between two tallest peaks\n",
    "\n",
    "You may want to plot the gated network in time-domain to see what the determined gate shape looks like."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.title('Waveguide Interface of Probe')\n",
    "s11.plot_s_db(label='original')\n",
    "s11.time_gate().plot_s_db(label='autogated') #autogate on the fly"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Might see how the autogate does on the other probe interface, "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.title('Other Interface of Probe')\n",
    "probe.s22.plot_s_db()\n",
    "probe.s22.time_gate().plot_s_db()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Determining Distance"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To make time-domain useful as a diagnostic tool, one would like to convert the x-axis to distance. This requires knowledge of the propagation velocity in the device.  **skrf** provides some transmission-line models in the module [skrf.media](../../api/media/index.rst), which  can be used for this.\n",
    "\n",
    "**However...**\n",
    "\n",
    "For dispersive media, such as rectangular waveguide, the phase velocity is a function of frequency, and transforming time to distance is not straightforward. As an approximation, you can normalize the x-axis to the speed of light.\n",
    "\n",
    "Alternatively, you can simulate the a known device and compare the two time domain responses. This allows you to attribute quantitative meaning to the axes. For example, you could create an ideal delayed load as shown below. Note: the magnitude of a response  *behind* a large impulse doesn not have meaningful units. \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from skrf.media import RectangularWaveguide\n",
    "\n",
    "# create a rectangular waveguide media to generate a theoretical network\n",
    "wr1p5 = RectangularWaveguide(frequency=probe.frequency,\n",
    "                             a=15*rf.mil,z0_override=1)\n",
    "\n",
    "# create an ideal delayed load, parameters are adjusted until the\n",
    "# theoretical response agrees with the measurement\n",
    "theory = wr1p5.delay_load(Gamma0=rf.db_2_mag(-20),\n",
    "                          d=2.4, unit='cm')\n",
    "\n",
    "\n",
    "probe.plot_s_db_time(0,0, label = 'Measurement')\n",
    "theory.plot_s_db_time(label='-20dB @ 2.4cm from test-port')\n",
    "plt.ylim(-100,0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This plot demonstrates a few important points:\n",
    "\n",
    "* the theoretical delayed load is not a perfect impulse in time. This is due to the dispersion in waveguide. \n",
    "* the peak of the magnitude in time domain is not identical to that specified, also due to dispersion (and windowing).\n",
    "\n",
    " "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## What the hell is Windowing?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `'plot_s_db_time()'` function does a few things. \n",
    "\n",
    "1. windows the s-parameters. \n",
    "*  converts to time domain  \n",
    "* takes magnitude component, convert to dB\n",
    "* calculates time-axis s\n",
    "* plots\n",
    "\n",
    "A word about step 1: **windowing**. A FFT represents a signal with a basis of periodic signals (sinusoids).  If your frequency response is not periodic, which in general it isn't, taking a FFT  will introduces artifacts in the time-domain results. To minimize these effects, the frequency response is *windowed*. This makes the frequency response more periodic by tapering off the band-edges. \n",
    "\n",
    "Windowing is just applied to improve the plot appearance,d it does not affect the original network.\n",
    "\n",
    "In skrf this can be done explicitly using the `'windowed()'` function.  By default this function uses the hamming window, but can be adjusted through arguments. The result of windowing is show below. \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "probe_w = probe.windowed()\n",
    "probe.plot_s_db(0,0, label = 'Original')\n",
    "probe_w.plot_s_db(0,0, label = 'Windowed')\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Comparing the two time-domain plotting functions, we can see the difference between windowed  and not. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "probe.plot_s_time_db(0,0, label = 'Original')\n",
    "probe_w.plot_s_time_db(0,0, label = 'Windowed')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.10"
  },
  "toc": {
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": "block",
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
